home *** CD-ROM | disk | FTP | other *** search
/ Space & Astronomy / Space and Astronomy (October 1993).iso / mac / VIEWERS / AMIGA / GIFMACHN.LZH / rlpsrc / iff / iff.h < prev    next >
C/C++ Source or Header  |  1991-05-04  |  21KB  |  512 lines

  1. #ifndef IFF_H
  2. #define IFF_H
  3. /*----------------------------------------------------------------------*/
  4. /* IFF.H  defs for IFF-85 Interchange Format Files.            1/22/86 */
  5. /*                                    */
  6. /* By Jerry Morrison and Steve Shaw, Electronic Arts.            */
  7. /* This software is in the public domain.                */
  8. /*----------------------------------------------------------------------*/
  9.  
  10. #ifndef COMPILER_H
  11. #include "iff/compiler.h"
  12. #endif
  13.  
  14. #ifndef LIBRARIES_DOS_H
  15. #include "libraries/dos.h"
  16. #endif
  17.  
  18. #ifndef OFFSET_BEGINNING
  19. #define OFFSET_BEGINNING OFFSET_BEGINING
  20. #endif
  21.  
  22. typedef LONG IFFP;    /* Status code result from an IFF procedure */
  23.     /* LONG, because must be type compatable with ID for GetChunkHdr.*/
  24.     /* Note that the error codes below are not legal IDs.*/
  25. #define IFF_OKAY   0L    /* Keep going...*/
  26. #define END_MARK  -1L    /* As if there was a chunk at end of group.*/
  27. #define IFF_DONE  -2L    /* clientProc returns this when it has READ enough.
  28.              * It means return thru all levels. File is Okay.*/
  29. #define DOS_ERROR -3L
  30. #define NOT_IFF   -4L    /* not an IFF file.*/
  31. #define NO_FILE   -5L    /* Tried to open file, DOS didn't find it.*/
  32. #define CLIENT_ERROR -6L /* Client made invalid request, for instance, write
  33.              * a negative size chunk.*/
  34. #define BAD_FORM  -7L    /* A client read proc complains about FORM semantics;
  35.              * e.g. valid IFF, but missing a required chunk.*/
  36. #define SHORT_CHUNK -8L    /* Client asked to IFFReadBytes more bytes than left
  37.              * in the chunk. Could be client bug or bad form.*/
  38. #define BAD_IFF   -9L    /* mal-formed IFF file. [TBD] Expand this into a
  39.              * range of error codes.*/
  40. #define LAST_ERROR BAD_IFF
  41.  
  42. /* This MACRO is used to RETURN immediately when a termination condition is
  43.  * found. This is a pretty weird macro. It requires the caller to declare a
  44.  * local "IFFP iffp" and assign it. This wouldn't work as a subroutine since
  45.  * it returns for it's caller.
  46.  */
  47. #define CheckIFFP()   { if (iffp != IFF_OKAY) return(iffp); }
  48.  
  49.  
  50. /* ---------- ID -------------------------------------------------------*/
  51.  
  52. typedef LONG ID;    /* An ID is four printable ASCII chars but
  53.              * stored as a LONG for efficient copy & compare.
  54.              */
  55.  
  56. /* Four-character IDentifier builder.*/
  57. #define MakeID(a,b,c,d)  ( (LONG)(a)<<24L | (LONG)(b)<<16L | (c)<<8 | (d) )
  58.  
  59. /* Standard group IDs.  A chunk with one of these IDs contains a
  60.  * SubTypeID followed by zero or more chunks.
  61.  */
  62. #define FORM MakeID('F','O','R','M')
  63. #define PROP MakeID('P','R','O','P')
  64. #define LIST MakeID('L','I','S','T')
  65. #define CAT  MakeID('C','A','T',' ')
  66. #define FILLER MakeID(' ',' ',' ',' ')
  67. /* The IDs "FOR1".."FOR9", "LIS1".."LIS9", & "CAT1".."CAT9" are reserved
  68.  * for future standardization.
  69.  */
  70.  
  71. /* Pseudo-ID used internally by chunk reader and writer.*/
  72. #define NULL_CHUNK 0L           /* No current chunk.*/
  73.  
  74.  
  75. /* ---------- Chunk ----------------------------------------------------*/
  76.  
  77. /* All chunks start with a type ID and a count of the data bytes that 
  78.  * follow--the chunk's "logicl size" or "data size". If that number is odd,
  79.  * a 0 pad byte is written, too.
  80.  */
  81. typedef struct {
  82.     ID      ckID;
  83.     LONG  ckSize;
  84.     } ChunkHeader;
  85.  
  86. typedef struct {
  87.     ID      ckID;
  88.     LONG  ckSize;
  89.     UBYTE ckData[ 1 /*REALLY: ckSize*/ ];
  90.     } Chunk;
  91.  
  92. /* Pass ckSize = szNotYetKnown to the writer to mean "compute the size".*/
  93. #define szNotYetKnown 0x80000001L
  94.  
  95. /* Need to know whether a value is odd so can word-align.*/
  96. #define IS_ODD(a)   ((a) & 1)
  97.  
  98. /* This macro rounds up to an even number. */
  99. #define WordAlign(size)   ((size+1)&~1)
  100.  
  101. /* ALL CHUNKS MUST BE PADDED TO EVEN NUMBER OF BYTES.
  102.  * ChunkPSize computes the total "physical size" of a padded chunk from
  103.  * its "data size" or "logical size".
  104.  */
  105. #define ChunkPSize(dataSize)  (WordAlign(dataSize) + sizeof(ChunkHeader))
  106.  
  107. /* The Grouping chunks (LIST, FORM, PROP, & CAT) contain concatenations of
  108.  * chunks after a subtype ID that identifies the content chunks.
  109.  * "FORM type XXXX", "LIST of FORM type XXXX", "PROPerties associated
  110.  * with FORM type XXXX", or "conCATenation of XXXX".
  111.  */
  112. typedef struct {
  113.     ID      ckID;
  114.     LONG  ckSize;    /* this ckSize includes "grpSubID".*/
  115.     ID    grpSubID;
  116.     } GroupHeader;
  117.  
  118. typedef struct {
  119.     ID      ckID;
  120.     LONG  ckSize;
  121.     ID    grpSubID;
  122.     UBYTE grpData[ 1 /*REALLY: ckSize-sizeof(grpSubID)*/ ];
  123.     } GroupChunk;
  124.  
  125.  
  126. /* ---------- IFF Reader -----------------------------------------------*/
  127.  
  128. /******** Routines to support a stream-oriented IFF file reader *******
  129.  *
  130.  * These routines handle lots of details like error checking and skipping
  131.  * over padding. They're also careful not to read past any containing context.
  132.  *
  133.  * These routines ASSUME they're the only ones reading from the file.
  134.  * Client should check IFFP error codes. Don't press on after an error!
  135.  * These routines try to have no side effects in the error case, except
  136.  * partial I/O is sometimes unavoidable.
  137.  *
  138.  * All of these routines may return DOS_ERROR. In that case, ask DOS for the
  139.  * specific error code.
  140.  *
  141.  * The overall scheme for the low level chunk reader is to open a "group read
  142.  * context" with OpenRIFF or OpenRGroup, read the chunks with GetChunkHdr
  143.  * (and its kin) and IFFReadBytes, and close the context with CloseRGroup.
  144.  *
  145.  * The overall scheme for reading an IFF file is to use ReadIFF, ReadIList,
  146.  * and ReadICat to scan the file. See those procedures, ClientProc (below),
  147.  * and the skeleton IFF reader.
  148.  */
  149.  
  150. /* Client passes ptrs to procedures of this type to ReadIFF which call them
  151.  * back to handle LISTs, FORMs, CATs, and PROPs.
  152.  *
  153.  * Use the GroupContext ptr when calling reader routines like GetChunkHdr.
  154.  * Look inside the GroupContext ptr for your ClientFrame ptr. You'll
  155.  * want to type cast it into a ptr to your containing struct to get your
  156.  * private contextual data (stacked property settings). See below.
  157.  */
  158. #ifdef FDwAT
  159. typedef IFFP ClientProc(struct _GroupContext *);
  160. #else
  161. typedef IFFP ClientProc();
  162. #endif
  163.  
  164. /* Client's context for reading an IFF file or a group.
  165.  * Client should actually make this the first component of a larger struct
  166.  * (it's personal stack "frame") that has a field to store each "interesting"
  167.  * property encountered.
  168.  * Either initialize each such field to a global default or keep a boolean
  169.  * indicating if you've read a property chunk into that field.
  170.  * Your getList and getForm procs should allocate a new "frame" and copy the
  171.  * parent frame's contents. The getProp procedure should store into the frame
  172.  * allocated by getList for the containing LIST.
  173.  */
  174. typedef struct _ClientFrame {
  175.    ClientProc *getList, *getProp, *getForm, *getCat;
  176.     /* client's own data follows; place to stack property settings */
  177.     } ClientFrame;
  178.  
  179. /* Our context for reading a group chunk. */
  180. typedef struct _GroupContext {
  181.     struct _GroupContext *parent; /* Containing group; NULL => whole file. */
  182.     ClientFrame *clientFrame;     /* Reader data & client's context state. */
  183.     BPTR file;        /* Byte-stream file handle. */
  184.     LONG position;    /* The context's logical file position. */
  185.     LONG bound;        /* File-absolute context bound
  186.              * or szNotYetKnown (writer only). */
  187.     ChunkHeader ckHdr;    /* Current chunk header. ckHdr.ckSize = szNotYetKnown
  188.              * means we need to go back and set the size (writer only).
  189.              * See also Pseudo-IDs, above. */
  190.     ID subtype;        /* Group's subtype ID when reading. */
  191.     LONG bytesSoFar;    /* # bytes read/written of current chunk's data. */
  192.     } GroupContext;
  193.  
  194. /* Computes the number of bytes not yet read from the current chunk, given
  195.  * a group read context gc.
  196.  */
  197. #define ChunkMoreBytes(gc)  ((gc)->ckHdr.ckSize - (gc)->bytesSoFar)
  198.  
  199.  
  200. /***** Low Level IFF Chunk Reader *****/
  201.  
  202. #ifdef FDwAT
  203.  
  204. /* Given an open file, open a read context spanning the whole file.
  205.  * This is normally only called by ReadIFF.
  206.  * This sets new->clientFrame = clientFrame.
  207.  * ASSUME context allocated by caller but not initialized.
  208.  * ASSUME caller doesn't deallocate the context before calling CloseRGroup.
  209.  * NOT_IFF ERROR if the file is too short for even a chunk header.
  210.  */
  211. extern IFFP OpenRIFF(BPTR, GroupContext *, ClientFrame *);
  212.              /*  file, new,            clientFrame  */
  213.  
  214. /* Open the remainder of the current chunk as a group read context.
  215.  * This will be called just after the group's subtype ID has been read
  216.  * (automatically by GetChunkHdr for LIST, FORM, PROP, and CAT) so the
  217.  * remainder is a sequence of chunks.
  218.  * This sets new->clientFrame = parent->clientFrame. The caller should repoint
  219.  * it at a new clientFrame if opening a LIST context so it'll have a "stack
  220.  * frame" to store PROPs for the LIST. (It's usually convenient to also
  221.  * allocate a new Frame when you encounter FORM of the right type.)
  222.  *
  223.  * ASSUME new context allocated by caller but not initialized.
  224.  * ASSUME caller doesn't deallocate the context or access the parent context
  225.  * before calling CloseRGroup.
  226.  * BAD_IFF ERROR if context end is odd or extends past parent. 
  227.  */
  228. extern IFFP OpenRGroup(GroupContext *, GroupContext *);
  229.            /*  parent,         new  */
  230.  
  231. /* Close a group read context, updating its parent context.
  232.  * After calling this, the old context may be deallocated and the parent
  233.  * context can be accessed again. It's okay to call this particular procedure
  234.  * after an error has occurred reading the group.
  235.  * This always returns IFF_OKAY.
  236.  */
  237. extern IFFP CloseRGroup(GroupContext *);
  238.             /*  old  */
  239.  
  240. /* Skip any remaining bytes of the previous chunk and any padding, then
  241.  * read the next chunk header into context.ckHdr.
  242.  * If the ckID is LIST, FORM, CAT, or PROP, this automatically reads the
  243.  * subtype ID into context->subtype.
  244.  * Caller should dispatch on ckID (and subtype) to an appropriate handler.
  245.  *
  246.  * RETURNS context.ckHdr.ckID (the ID of the new chunk header); END_MARK
  247.  * if there are no more chunks in this context; or NOT_IFF if the top level
  248.  * file chunk isn't a FORM, LIST, or CAT; or BAD_IFF if malformed chunk, e.g.
  249.  * ckSize is negative or too big for containing context, ckID isn't positive,
  250.  * or we hit end-of-file.
  251.  *
  252.  * See also GetFChunkHdr, GetF1ChunkHdr, and GetPChunkHdr, below.
  253.  */
  254. extern ID       GetChunkHdr(GroupContext *);
  255.   /*  context.ckHdr.ckID    context  */
  256.  
  257. /* Read nBytes number of data bytes of current chunk. (Use OpenGroup, etc.
  258.  * instead to read the contents of a group chunk.) You can call this several
  259.  * times to read the data piecemeal.
  260.  * CLIENT_ERROR if nBytes < 0. SHORT_CHUNK if nBytes > ChunkMoreBytes(context)
  261.  * which could be due to a client bug or a chunk that's shorter than it
  262.  * ought to be (bad form). (on either CLIENT_ERROR or SHORT_CHUNK,
  263.  * IFFReadBytes won't read any bytes.)
  264.  */
  265. extern IFFP IFFReadBytes(GroupContext *, BYTE *, LONG);
  266.              /*  context,        buffer, nBytes  */
  267.  
  268.  
  269. /***** IFF File Reader *****/
  270.  
  271. /* This is a noop ClientProc that you can use for a getList, getForm, getProp,
  272.  * or getCat procedure that just skips the group. A simple reader might just
  273.  * implement getForm, store ReadICat in the getCat field of clientFrame, and
  274.  * use SkipGroup for the getList and getProp procs.
  275.  */
  276. extern IFFP SkipGroup(GroupContext *);
  277.  
  278. /* IFF file reader.
  279.  * Given an open file, allocate a group context and use it to read the FORM,
  280.  * LIST, or CAT and it's contents. The idea is to parse the file's contents,
  281.  * and for each FORM, LIST, CAT, or PROP encountered, call the getForm,
  282.  * getList, getCat, or getProp procedure in clientFrame, passing the
  283.  * GroupContext ptr.
  284.  * This is achieved with the aid of ReadIList (which your getList should
  285.  * call) and ReadICat (which your getCat should call, if you don't just use
  286.  * ReadICat for your getCat). If you want to handle FORMs, LISTs, and CATs
  287.  * nested within FORMs, the getForm procedure must dispatch to getForm,
  288.  * getList, and getCat (it can use GetF1ChunkHdr to make this easy).
  289.  *
  290.  * Normal return is IFF_OKAY (if whole file scanned) or IFF_DONE (if a client
  291.  * proc said "done" first).
  292.  * See the skeletal getList, getForm, getCat, and getProp procedures.
  293.  */
  294. extern IFFP ReadIFF(BPTR, ClientFrame *);
  295.                 /*  file, clientFrame  */
  296.  
  297. /* IFF LIST reader.
  298.  * Your "getList" procedure should allocate a ClientFrame, copy the parent's
  299.  * ClientFrame, and then call this procedure to do all the work.
  300.  *
  301.  * Normal return is IFF_OKAY (if whole LIST scanned) or IFF_DONE (if a client
  302.  * proc said "done" first).
  303.  * BAD_IFF ERROR if a PROP appears after a non-PROP.
  304.  */
  305. extern IFFP ReadIList(GroupContext *, ClientFrame *);
  306.           /*  parent,         clientFrame  */
  307.  
  308. /* IFF CAT reader.
  309.  * Most clients can simply use this to read their CATs. If you must do extra
  310.  * setup work, put a ptr to your getCat procedure in the clientFrame, and
  311.  * have that procedure call ReadICat to do the detail work.
  312.  *
  313.  * Normal return is IFF_OKAY (if whole CAT scanned) or IFF_DONE (if a client
  314.  * proc said "done" first).
  315.  * BAD_IFF ERROR if a PROP appears in the CAT.
  316.  */
  317. extern IFFP ReadICat(GroupContext *);
  318.          /*  parent  */
  319.  
  320. /* Call GetFChunkHdr instead of GetChunkHdr to read each chunk inside a FORM.
  321.  * It just calls GetChunkHdr and returns BAD_IFF if it gets a PROP chunk.
  322.  */
  323. extern ID    GetFChunkHdr(GroupContext *);
  324.   /*  context.ckHdr.ckID    context  */
  325.  
  326. /* GetF1ChunkHdr is like GetFChunkHdr, but it automatically dispatches to the
  327.  * getForm, getList, and getCat procedure (and returns the result) if it
  328.  * encounters a FORM, LIST, or CAT.
  329.  */
  330. extern ID    GetF1ChunkHdr(GroupContext *);
  331.   /*  context.ckHdr.ckID    context  */
  332.  
  333. /* Call GetPChunkHdr instead of GetChunkHdr to read each chunk inside a PROP.
  334.  * It just calls GetChunkHdr and returns BAD_IFF if it gets a group chunk.
  335.  */
  336. extern ID    GetPChunkHdr(GroupContext *);
  337.   /*  context.ckHdr.ckID    context  */
  338.  
  339. #else /* not FDwAT */
  340.  
  341. extern IFFP OpenRIFF();
  342. extern IFFP OpenRGroup();
  343. extern IFFP CloseRGroup();
  344. extern ID   GetChunkHdr();
  345. extern IFFP IFFReadBytes();
  346. extern IFFP SkipGroup();
  347. extern IFFP ReadIFF();
  348. extern IFFP ReadIList();
  349. extern IFFP ReadICat();
  350. extern ID   GetFChunkHdr();
  351. extern ID   GetF1ChunkHdr();
  352. extern ID   GetPChunkHdr();
  353.  
  354. #endif /* not FDwAT */
  355.  
  356. /* ---------- IFF Writer -----------------------------------------------*/
  357.  
  358. /******* Routines to support a stream-oriented IFF file writer *******
  359.  *
  360.  * These routines will random access back to set a chunk size value when the
  361.  * caller doesn't know it ahead of time. They'll also do things automatically
  362.  * like padding and error checking.
  363.  *
  364.  * These routines ASSUME they're the only ones writing to the file.
  365.  * Client should check IFFP error codes. Don't press on after an error!
  366.  * These routines try to have no side effects in the error case, except that
  367.  * partial I/O is sometimes unavoidable.
  368.  *
  369.  * All of these routines may return DOS_ERROR. In that case, ask DOS for the
  370.  * specific error code.
  371.  *
  372.  * The overall scheme is to open an output GroupContext via OpenWIFF or
  373.  * OpenWGroup, call either PutCk or {PutCkHdr {IFFWriteBytes}* PutCkEnd} for
  374.  * each chunk, then use CloseWGroup to close the GroupContext.
  375.  *
  376.  * To write a group (LIST, FORM, PROP, or CAT), call StartWGroup, write out
  377.  * its chunks, then call EndWGroup. StartWGroup automatically writes the
  378.  * group header and opens a nested context for writing the contents.
  379.  * EndWGroup closes the nested context and completes the group chunk.
  380.  */
  381.  
  382.  
  383. #ifdef FDwAT
  384.  
  385. /* Given a file open for output, open a write context.
  386.  * The "limit" arg imposes a fence or upper limit on the logical file
  387.  * position for writing data in this context. Pass in szNotYetKnown to be
  388.  * bounded only by disk capacity.
  389.  * ASSUME new context structure allocated by caller but not initialized.
  390.  * ASSUME caller doesn't deallocate the context before calling CloseWGroup.
  391.  * The caller is only allowed to write out one FORM, LIST, or CAT in this top
  392.  * level context (see StartWGroup and PutCkHdr).
  393.  * CLIENT_ERROR if limit is odd.
  394.  */
  395. extern IFFP OpenWIFF(BPTR, GroupContext *, LONG);
  396.          /*  file, new,            limit {file position}  */
  397.  
  398. /* Start writing a group (presumably LIST, FORM, PROP, or CAT), opening a
  399.  * nested context. The groupSize includes all nested chunks + the subtype ID.
  400.  *
  401.  * The subtype of a LIST or CAT is a hint at the contents' FORM type(s). Pass
  402.  * in FILLER if it's a mixture of different kinds.
  403.  *
  404.  * This writes the chunk header via PutCkHdr, writes the subtype ID via
  405.  * IFFWriteBytes, and calls OpenWGroup. The caller may then write the nested
  406.  * chunks and finish by calling EndWGroup.
  407.  * The OpenWGroup call sets new->clientFrame = parent->clientFrame.
  408.  *
  409.  * ASSUME new context structure allocated by caller but not initialized.
  410.  * ASSUME caller doesn't deallocate the context or access the parent context
  411.  * before calling CloseWGroup.
  412.  * ERROR conditions: See PutCkHdr, IFFWriteBytes, OpenWGroup.
  413.  */
  414. extern IFFP StartWGroup(GroupContext *, ID, LONG, ID, GroupContext *);
  415.             /*  parent, groupType, groupSize, subtype, new  */
  416.  
  417. /* End a group started by StartWGroup.
  418.  * This just calls CloseWGroup and PutCkEnd.
  419.  * ERROR conditions: See CloseWGroup and PutCkEnd.
  420.  */
  421. extern IFFP EndWGroup(GroupContext *);
  422.             /*  old  */
  423.  
  424. /* Open the remainder of the current chunk as a group write context.
  425.  * This is normally only called by StartWGroup.
  426.  *
  427.  * Any fixed limit to this group chunk or a containing context will impose
  428.  * a limit on the new context.
  429.  * This will be called just after the group's subtype ID has been written
  430.  * so the remaining contents will be a sequence of chunks.
  431.  * This sets new->clientFrame = parent->clientFrame.
  432.  * ASSUME new context structure allocated by caller but not initialized.
  433.  * ASSUME caller doesn't deallocate the context or access the parent context
  434.  * before calling CloseWGroup.
  435.  * CLIENT_ERROR if context end is odd or PutCkHdr wasn't called first.
  436.  */
  437. extern IFFP OpenWGroup(GroupContext *, GroupContext *);
  438.            /*  parent,         new  */
  439.  
  440. /* Close a write context and update its parent context.
  441.  * This is normally only called by EndWGroup.
  442.  *
  443.  * If this is a top level context (created by OpenWIFF) we'll set the file's
  444.  * EOF (end of file) but won't close the file.
  445.  * After calling this, the old context may be deallocated and the parent
  446.  * context can be accessed again.
  447.  *
  448.  * Amiga DOS Note: There's no call to set the EOF. We just position to the
  449.  * desired end and return. Caller must Close file at that position.
  450.  * CLIENT_ERROR if PutCkEnd wasn't called first.
  451.  */
  452. extern IFFP CloseWGroup(GroupContext *);
  453.             /*  old  */
  454.  
  455. /* Write a whole chunk to a GroupContext. This writes a chunk header, ckSize
  456.  * data bytes, and (if needed) a pad byte. It also updates the GroupContext.
  457.  * CLIENT_ERROR if ckSize == szNotYetKnown. See also PutCkHdr errors.
  458.  */
  459. extern IFFP PutCk(GroupContext *, ID,   LONG,   BYTE *);
  460.           /*  context,        ckID, ckSize, *data  */
  461.  
  462. /* Write just a chunk header. Follow this will any number of calls to
  463.  * IFFWriteBytes and finish with PutCkEnd.
  464.  * If you don't yet know how big the chunk is, pass in ckSize = szNotYetKnown,
  465.  * then PutCkEnd will set the ckSize for you later.
  466.  * Otherwise, IFFWriteBytes and PutCkEnd will ensure that the specified
  467.  * number of bytes get written.
  468.  * CLIENT_ERROR if the chunk would overflow the GroupContext's bound, if
  469.  * PutCkHdr was previously called without a matching PutCkEnd, if ckSize < 0
  470.  * (except szNotYetKnown), if you're trying to write something other
  471.  * than one FORM, LIST, or CAT in a top level (file level) context, or
  472.  * if ckID <= 0 (these illegal ID values are used for error codes).
  473.  */
  474. extern IFFP PutCkHdr(GroupContext *, ID,   LONG);
  475.          /*  context,        ckID, ckSize  */
  476.  
  477. /* Write nBytes number of data bytes for the current chunk and update
  478.  * GroupContext.
  479.  * CLIENT_ERROR if this would overflow the GroupContext's limit or the
  480.  * current chunk's ckSize, or if PutCkHdr wasn't called first, or if
  481.  * nBytes < 0.
  482.  */
  483. extern IFFP IFFWriteBytes(GroupContext *, BYTE *, LONG);
  484.               /*  context,        *data,  nBytes  */
  485.  
  486. /* Complete the current chunk, write a pad byte if needed, and update
  487.  * GroupContext.
  488.  * If current chunk's ckSize = szNotYetKnown, this goes back and sets the
  489.  * ckSize in the file.
  490.  * CLIENT_ERROR if PutCkHdr wasn't called first, or if client hasn't
  491.  * written 'ckSize' number of bytes with IFFWriteBytes.
  492.  */
  493. extern IFFP PutCkEnd(GroupContext *);
  494.          /*  context  */
  495.  
  496. #else /* not FDwAT */
  497.  
  498. extern IFFP OpenWIFF();
  499. extern IFFP StartWGroup();
  500. extern IFFP EndWGroup();
  501. extern IFFP OpenWGroup();
  502. extern IFFP CloseWGroup();
  503. extern IFFP PutCk();
  504. extern IFFP PutCkHdr();
  505. extern IFFP IFFWriteBytes();
  506. extern IFFP PutCkEnd();
  507.  
  508. #endif /* not FDwAT */
  509.  
  510. #endif IFF_H
  511.  
  512.